﻿using System.Management.Automation;
using DotNet.DevOps.Tasks.Service;
using DotNet.DevOps.Tasks.Util;

namespace DotNet.DevOps.Tasks.Cmdlets
{
    /// <summary>
    /// Can install a new or replace an existing windows service.
    /// The following actions are taking, in order.
    /// 
    /// * Stop
    /// * Uninstall
    /// * Copy (unzip if needed)
    /// * Install
    /// * Start 
    /// 
    /// on a local or remote machine.
    /// It is possible to define logon user, timeout and service description, among other things.
    /// 
    /// Requirements:
    /// * The user under which the task is executed must have the correct rights to install, uninstall, start, stop, copy on the local/remote machine.
    /// 
    /// Default behaviour:
    /// * Installs service to run under SYSTEM account.
    /// * Installs on this machine if no machine specified.
    /// * Installs with default description, service name.
    /// * No timeout.
    /// </summary>
    /// <example>
    /// import-module .\DotNet.DevOps.Tasks.dll
    /// import-module .\Ionic.Zip.Reduced.dll
    /// 
    /// $serviceProps = @{
    ///     Name = "TestService"
    ///     Machine = "TESTSERVER" 
    ///     ServiceExecutable = "NServiceBus.Host.Exe" 
    ///     ServiceArguments = "-service MSBuild.DevOps.Tasks.Tests.dll /serviceName:TestService" 
    ///     SourcePath = "MyService.zip" 
    ///     DestinationPath = "\\Server\MyService" 
    ///     Description = "This is my service" 
    ///     Startup = "demand"
    ///     Timeout = "30000"
    /// }
    /// 
    /// Install-Service -Property $serviceProps
    /// </example>
    [Cmdlet(VerbsLifecycle.Install, "Service", ConfirmImpact = ConfirmImpact.High, SupportsShouldProcess = false, SupportsTransactions = false)]
    public class Install_Service : Cmdlet, IInstallService
    {
        /// <summary>
        /// Name of the service to deploy.
        /// </summary>
        [Parameter(Mandatory = true, Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string Name { get; set; }
        /// <summary>
        /// Name of the machine on which to install the service. Default to this machine.
        /// </summary>
        [Parameter(Mandatory = false, Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string Machine { get; set; }
        /// <summary>
        /// Name of the user under which the service will execute. Defaults to SYSTEM.
        /// </summary>
        [Parameter(Mandatory = false, Position = 2, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string LogonAsUser { get; set; }
        /// <summary>
        /// Password of the user under which the service will execute. Will be auto prefixed with machine name if you forget.
        /// </summary>
        [Parameter(Mandatory = false, Position = 3, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string LogonAsPassword { get; set; }
        /// <summary>
        /// Name of the service executable.
        /// </summary>
        [Parameter(Mandatory = true, Position = 4, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string ServiceExecutable { get; set; }
        /// <summary>
        /// Arguments to the service executable.
        /// </summary>
        [Parameter(Mandatory = false, Position = 5, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string ServiceArguments { get; set; }
        /// <summary>
        /// Path where the service binaries can be found. Zip files will be unpacked directly into destination.
        /// </summary>
        [Parameter(Mandatory = true, Position = 6, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string SourcePath { get; set; }
        /// <summary>
        /// Path where the service binaries must be placed.
        /// </summary>
        [Parameter(Mandatory = true, Position = 7, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string DestinationPath { get; set; }
        /// <summary>
        /// Description of service to display in service.msc.
        /// </summary>
        [Parameter(Mandatory = false, Position = 8, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string Description { get; set; }
        /// <summary>
        /// Specifies wether the service should be started upon successfull completion of the install. Default true.
        /// </summary>
        [Parameter(Mandatory = false, Position = 9, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public bool StartWhenDone { get; set; }
        /// <summary>
        /// Specifies the service startup type. Valid values are: auto, demand, disabled. Default auto.
        /// </summary>
        [Parameter(Mandatory = false, Position = 10, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public string Startup { get; set; }
        /// <summary>
        /// Complete timeout, in milliseconds, for all the service command which might fire (Stop, Uninstall, Copy, Install, Start). Default infinte.
        /// </summary>
        [Parameter(Mandatory = false, Position = 11, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
        public int Timeout { get; set; }

        private InstallService task;

        public Install_Service()
        {
            task = new InstallService(new PowershellCmdletLogger(this));
            Timeout = task.Timeout;
        }

        protected override void BeginProcessing()
        {
            task = new InstallService(new PowershellCmdletLogger(this))
                .CopyPropertyValuesFrom(this) as InstallService;
        }

        protected override void ProcessRecord()
        {
            task.Execute();
        }
    }
}
